package sunwul.mall.gateway.config;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceInstance;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import sunwul.mall.gateway.constant.ServiceGroupEnum;

import java.util.*;

/**
 * @author sunwul
 * @date 2025/1/2 15:01
 * @description nacos服务发现配置类
 * nacos的默认调用机制是同namespace下的同group的服务才可以相互调用,
 * 由于业务服务与基础服务不在同一group下, 会出现gateway无法找到业务服务, 导致404错误
 */
@Slf4j
@Component
public class NacosServiceDiscoveryV2 extends NacosServiceDiscovery {

    private NacosDiscoveryProperties discoveryProperties;
    private NacosServiceManager nacosServiceManager;

    public NacosServiceDiscoveryV2(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) {
        super(discoveryProperties, nacosServiceManager);
        this.discoveryProperties = discoveryProperties;
        this.nacosServiceManager = nacosServiceManager;
    }

    @Override
    public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
        // 获取分组
        String group = this.discoveryProperties.getGroup();
        // 查找服务, 优先保证同一group下的服务调用, 同一group下未找到服务, 查询其他group下的服务
        List<Instance> instances = this.nacosServiceManager.getNamingService(this.discoveryProperties.
                getNacosProperties()).selectInstances(serviceId, group, true);
//        log.info("getInstances -1 -"+serviceId + "- group=" + this.discoveryProperties.getGroup()
//                + " - exist=" + CollUtil.isNotEmpty(instances));
        if (CollUtil.isNotEmpty(instances)) {
            return hostToServiceInstanceList(instances, serviceId);
        }

        // 其他分组的实例,此时排除上面已经查找过的group
        List<ServiceInstance> list = new ArrayList<>();
        for (String s : ServiceGroupEnum.getValue(group)) {
            instances = this.nacosServiceManager.getNamingService(this.discoveryProperties.
                    getNacosProperties()).selectInstances(serviceId, s, true);
//            log.info("getInstances -2 -"+serviceId + "- group=" + s + " - exist=" + CollUtil.isNotEmpty(instances));
            if (CollUtil.isNotEmpty(instances)) {
                list.addAll(hostToServiceInstanceList(instances, serviceId));
            }
        }
        return list;
    }

    // 获取所有服务 - 除同一group下的服务, 也获取其他group的
    @Override
    public List<String> getServices() throws NacosException {
        List<String> list = new ArrayList<>();
        // 当前分组
        String group = this.discoveryProperties.getGroup();
        ListView<String> listView1 = this.nacosServiceManager.getNamingService(this.discoveryProperties.
                getNacosProperties()).getServicesOfServer(1, Integer.MAX_VALUE, group);
        if (CollUtil.isNotEmpty(listView1.getData())) {
            list.addAll(listView1.getData());
        }

        // 其他分组, 此时排除上面已经查找过的group
        for (String s : ServiceGroupEnum.getValue(group)) {
            ListView<String> listView2 = this.nacosServiceManager.getNamingService(this.discoveryProperties.
                    getNacosProperties()).getServicesOfServer(1, Integer.MAX_VALUE, s);
//            log.info("group - " + s + listView2.toString());
            if (CollUtil.isNotEmpty(listView2.getData())) {
                list.addAll(listView2.getData());
            }
        }
        return list;
    }

    /**
     * 获取实例列表
     */
    public static List<ServiceInstance> hostToServiceInstanceList(List<Instance> instances, String serviceId) {
        List<ServiceInstance> result = new ArrayList<>(instances.size());

        for (Instance instance : instances) {
            ServiceInstance serviceInstance = hostToServiceInstance(instance, serviceId);
            if (serviceInstance != null) {
//                log.info("metadata: " + serviceInstance.getMetadata());
                result.add(serviceInstance);
            }
        }

        return result;
    }

    /**
     * 实例信息组装
     */
    public static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) {
        if (instance == null || !instance.isEnabled() || !instance.isHealthy()) {
            return null;
        }
        NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
        nacosServiceInstance.setHost(instance.getIp());
        nacosServiceInstance.setPort(instance.getPort());
        nacosServiceInstance.setServiceId(serviceId);
        nacosServiceInstance.setInstanceId(instance.getInstanceId());

        Map<String, String> metadata = new HashMap<>();
        metadata.put("nacos.instanceId", instance.getInstanceId());
        metadata.put("nacos.weight", String.valueOf(instance.getWeight()));
        metadata.put("nacos.healthy", String.valueOf(instance.isHealthy())); // 心跳
        metadata.put("nacos.cluster", instance.getClusterName()); // 集群
        if (instance.getMetadata() != null) {
            metadata.putAll(instance.getMetadata());
        }
        metadata.put("nacos.ephemeral", String.valueOf(instance.isEphemeral()));

        // 服务信息拆分 192.168.43.150#8081#DEFAULT#BUSINESS_GROUP@@manager-service
        String[] strings = instance.getInstanceId().split("#");
        metadata.put("service.addr", strings[0] + ":" + strings[1]);
        metadata.put("service.group", strings[3].split("@@")[0]);
        metadata.put("service.name", strings[3].split("@@")[1]);
//        if (instance.getMetadata() != null) {
//            metadata.putAll(instance.getMetadata());
//        }

        nacosServiceInstance.setMetadata(metadata);
        if (metadata.containsKey("secure")) {
            boolean secure = Boolean.parseBoolean(metadata.get("secure")); // 受保护
            nacosServiceInstance.setSecure(secure);
        }
        return nacosServiceInstance;
    }
}
